﻿using Library.Common.Common;
using Library.Common.Model;
using Library.Common.Serialize;
using Library.Core.Application;
using Library.Core.Application.BaseAction;
using Library.Core.Application.IInfrastructure;
using Library.Core.Application.IInfrastructure.EntityFrameworkDataAccess;
using Library.Core.Application.IInfrastructure.Event;
using Synthesize.BaseSet.Application.MessageTopic;
using Synthesize.BaseSet.Domain.Aggregation.Consts;
using Synthesize.BaseSet.Domain.Aggregation.Entity.Authority;
using Synthesize.BaseSet.Domain.Event.Authority;
using Synthesize.BaseSet.Domain.Repository.Authority;
using Synthesize.BaseSet.ServiceInterface.Dtos.Authority.User;
using Synthesize.BaseSet.ServiceInterface.UseCase.Authority;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;

namespace Synthesize.BaseSet.Application.UseCase.Authority
{
    /// <summary>
    /// 用户信息操作类
    /// </summary>
    public class UserService : BaseService, IUserService
    {
        private readonly IJwtFactory _jwtFactory;
        private readonly IEventBus _eventBus;
        private readonly ITransaction _transaction;
        private readonly IUserRepository _userRepository;
        private readonly IUserRoleRepository _userRoleRepository;
        private readonly IUserDepartmentRepository _userDepartmentRepository;
        private readonly IUserPostRepository _userPostRepository;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="container"></param>
        /// <param name="jwtFactory"></param>
        /// <param name="eventBus"></param>
        /// <param name="transaction"></param>
        /// <param name="userRepository"></param>
        /// <param name="userRoleRepository"></param>
        /// <param name="userDepartmentRepository"></param>
        /// <param name="userPostRepository"></param>
        public UserService(IIocContainer container
            , IJwtFactory jwtFactory
            , IEventBus eventBus
            , ITransaction transaction
            , IUserRepository userRepository
            , IUserRoleRepository userRoleRepository
            , IUserDepartmentRepository userDepartmentRepository
            , IUserPostRepository userPostRepository
            ) : base(container)
        {
            _jwtFactory = jwtFactory;
            _eventBus = eventBus;
            _transaction = transaction;
            _userRepository = userRepository;
            _userRoleRepository = userRoleRepository;
            _userDepartmentRepository = userDepartmentRepository;
            _userPostRepository = userPostRepository;
        }

        /// <summary>
        /// 添加用户信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> Create(RegisterUserInput input)
        {

            return await HandleAsync(input, async () =>
            {
                var result = false;

                if (input.Password != input.Password2)
                {
                    throw new ApplicationsException("两次输入密码不一致.");
                }
                if (await _userRepository.AnyAsync(x => x.UserName == input.UserName))
                {
                    throw new ApplicationsException("创建的登陆账号不能重复");
                }

                using (var tran = _transaction.BeginTransactionEF())
                {
                    //仓储添加用户
                    input.PictureUrl = HttpUtility.UrlDecode(input.PictureUrl);
                    var user = MapperHelper<RegisterUserInput, UserInfoEntity>.Map(input);
                    user.Id = GuidHelper.GetSecuentialGuid();
                    user.IsValid = true;
                    await _userRepository.AddAsync(user);

                    //添加用户-角色
                    if ((input.RoleIds?.Count ?? 0) > 0)
                    {
                        var userRoles = input.RoleIds.Select(x => new UserRoleReEntity { UserId = user.Id, RoleId = x });
                        await _userRoleRepository.AddRangeAsync(userRoles);
                    }

                    //添加用户-部门
                    var userDepartment = new UserDepartmentReEntity { UserId = user.Id, DepartmentId = input.DepartmentId };
                    await _userDepartmentRepository.AddAsync(userDepartment);

                    //添加用户-崗位
                    if ((input.PostIds?.Count ?? 0) > 0)
                    {
                        var userPosts = input.PostIds.Select(x => new UserPostReEntity { UserId = user.Id, PostId = x });
                        await _userPostRepository.AddRangeAsync(userPosts);
                    }

                    result = await _userRepository.SaveAsync();

                    await tran.CommitAsync();

                    return result;
                }

            });
        }

        /// <summary>
        /// 编辑用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> Update(UpdateUserInput input)
        {

            return await HandleAsync(input, async () =>
            {
                var result = false;

                if (await _userRepository.AnyAsync(x => x.UserName == input.UserName && x.Id != input.Id))
                {
                    throw new ApplicationsException("登陆账号不能重复");
                }

                using (var tran = _transaction.BeginTransactionEF())
                {
                    var user = await _userRepository.GetAsync(x => x.Id.Equals(input.Id));
                    if (user == null)
                    {
                        throw new ApplicationsException("没有找到该用户!");
                    }

                    //仓储操作用户
                    var oldPsw = user.Password;
                    var oldIsValid = user.IsValid;
                    input.PictureUrl = HttpUtility.UrlDecode(input.PictureUrl);
                    user = MapperHelper<UpdateUserInput, UserInfoEntity>.Map(input);
                    user.Password = oldPsw;
                    user.IsValid = oldIsValid;
                    _userRepository.Update(user);

                    //用户-角色
                    var oldRoles = await _userRoleRepository.GetManyAsync(x => x.UserId.Equals(input.Id));
                    if (oldRoles.Any())
                    {
                        foreach (var item in oldRoles)
                        {
                            _userRoleRepository.Delete(item);
                        }
                    }
                    if ((input.RoleIds?.Count ?? 0) > 0)
                    {
                        var userRoles = input.RoleIds.Select(x => new UserRoleReEntity { UserId = user.Id, RoleId = x });
                        await _userRoleRepository.AddRangeAsync(userRoles);
                    }

                    //用户-部门
                    var oldUserDepartment = await _userDepartmentRepository.GetAsync(x => x.UserId.Equals(input.Id));
                    if (oldUserDepartment != null)
                    {
                        _userDepartmentRepository.Delete(oldUserDepartment);
                    }
                    var userDepartment = new UserDepartmentReEntity { UserId = user.Id, DepartmentId = input.DepartmentId };
                    await _userDepartmentRepository.AddAsync(userDepartment);

                    //用户-岗位
                    var oldPosts = await _userPostRepository.GetManyAsync(x => x.UserId.Equals(input.Id));
                    if (oldPosts.Any())
                    {
                        foreach (var item in oldPosts)
                        {
                            _userPostRepository.Delete(item);
                        }
                    }
                    if ((input.PostIds?.Count ?? 0) > 0)
                    {
                        var userPosts = input.PostIds.Select(x => new UserPostReEntity { UserId = user.Id, PostId = x });
                        await _userPostRepository.AddRangeAsync(userPosts);
                    }

                    //如果之前的角色被去掉，就需要强制账号退出
                    if (oldRoles.Any() && oldRoles.Exists(x => !input.RoleIds.Contains(x.RoleId)))
                    {
                        await NotifyForceLogOut(new List<Guid>() { input.Id });
                    }

                    result = await _userRepository.SaveAsync();
                    await tran.CommitAsync();
                    return result;
                }
            });
        }

        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> ResetPassword(ResetUserPasswordInput input)
        {

            return await HandleAsync(input, async () =>
            {
                var info = await _userRepository.GetAsync(x => x.Id == input.Id);
                if (info == null)
                {
                    throw new ApplicationsException("无对应用户信息！");
                }
                info.ResetPassword();
                _userRepository.Update(info);

                return await _userRepository.SaveAsync();
            });
        }

        /// <summary>
        /// 禁用/启用用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> ForbidOrEnable(ForbidOrEnableInput input)
        {

            return await HandleAsync(input, async () =>
            {
                var info = await _userRepository.GetAsync(x => x.Id == input.Id);
                if (info == null)
                {
                    throw new ApplicationsException("无对应用户信息！");
                }
                info.IsValid = !info.IsValid;
                _userRepository.Update(info);

                if (!info.IsValid)
                {
                    //做强退通知
                    await NotifyForceLogOut(new List<Guid>() { input.Id });
                }
                return await _userRepository.SaveAsync();
            });
        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> DeleteById(SingleDeleteInput input)
        {
            return await HandleAsync(input, async () =>
            {
                var result = false;
                using (var tran = _transaction.BeginTransactionEF())
                {
                    var info = await _userRepository.GetAsync(x => input.Id == x.Id);
                    if (info == null)
                    {
                        throw new ApplicationsException("无对应用户信息！");
                    }
                    _userRepository.UpdateIsDeleted(info);

                    //删除角色用户关系
                    var oldRoles = await _userRoleRepository.GetManyAsync(x => x.UserId.Equals(input.Id));
                    if (oldRoles.Any())
                    {
                        foreach (var item in oldRoles)
                        {
                            _userRoleRepository.Delete(item);
                        }
                    }

                    //删除部门-用户关系
                    var oldUserDepartment = await _userDepartmentRepository.GetAsync(x => x.UserId.Equals(input.Id));
                    if (oldUserDepartment != null)
                    {
                        _userDepartmentRepository.Delete(oldUserDepartment);
                    }

                    //删除岗位-用户关系
                    var oldPosts = await _userPostRepository.GetManyAsync(x => x.UserId.Equals(input.Id));
                    if (oldPosts.Any())
                    {
                        foreach (var item in oldPosts)
                        {
                            _userPostRepository.Delete(item);
                        }
                    }

                    result = await _userRepository.SaveAsync();
                    await tran.CommitAsync();

                    //做强退通知
                    await NotifyForceLogOut(new List<Guid>() { input.Id });

                    return result;
                }

            });
        }

        /// <summary>
        /// 做强退通知
        /// </summary>
        /// <param name="userIdList"></param>
        /// <returns></returns>
        private async Task NotifyForceLogOut(List<Guid> userIdList)
        {
            var userList = await _userRepository.GetManyAsync(x => userIdList.Contains(x.Id));
            await _jwtFactory.MakeUserAllTokenInvalid(userList.Select(x => x.UserName).ToList());
            if (userList.Count > 0)
            {
                var messages = new List<SendMessageEvent>();
                foreach (var item in userList)
                {
                    await _eventBus.PublishAsync(TopicName.SendMessage,
                        new SendMessageEvent(
                            "强制退出登录",
                            $"用户{item.UserName}关键信息变更，需强制退出登录",
                            Guid.Empty,
                            item.Id,
                            DateTime.Now,
                            string.Empty,
                            string.Empty,
                            SendMessageCode.ForceLogOut
                       )
                    );
                }
            }
        }
    }
}
